/*

 ARCHIVO: "complex.h"

 Declaración de la clase complejo.

 Primera versión: 23-3-2012

*/


#ifndef _COMPLEJO_H_INCLUDED_
#define _COMPLEJO_H_INCLUDED_


#include <iostream>


// En caso de no estar definidas las constantes numéricas,
// las defino (En general los compiladores de GNU las definen,
// si no se trabaja en modo ANSI estricto).

#ifndef M_PI

#define M_E         2.7182818284590452354
#define M_LOG2E     1.4426950408889634074
#define M_LOG10E    0.43429448190325182765
#define M_LN2       0.69314718055994530942
#define M_LN10      2.30258509299404568402
#define M_PI        3.14159265358979323846
#define M_PI_2      1.57079632679489661923
#define M_PI_4      0.78539816339744830962
#define M_1_PI      0.31830988618379067154
#define M_2_PI      0.63661977236758134308
#define M_2_SQRTPI  1.12837916709551257390
#define M_SQRT2     1.41421356237309504880
#define M_SQRT1_2   0.70710678118654752440

#endif


class complejo
{
private:
    // Atributo que contiene la parte real.
    double re_;

    // Atributo que contiene la parte imaginaria.
    double im_;

public:

    //Constructor en base a dos doubles, pudiendo ser interpreatdos en forma cartesiana o polar
    //según el valor de bpolar.
    complejo(double da=0.0, double db=0.0, bool bpolar=false);

    //Constructor copia.
    complejo(const complejo &cmr);

    //Destructor.
    ~complejo();

    //Parte real del complejo.
    double real() const;

    //Parte imaginaria del complejo.
    double imag() const;

    //Módulo del complejo.
    double abs() const;

    //Módulo del complejo al cuadrado, igual al complejo por su conjugado.
    double abs_cuad() const;

    //Argumento del complejo.
    double arg() const;

    //Conjuga la instancia del complejo.
    complejo& conjugar();

    //Devuelve otro complejo que es el conjugado de la instancia de complejo.
    complejo conjugado() const;


    /* Operadores - Begin */

    //Operador asignación (complejo).
    complejo& operator=(const complejo &cmr);

    //Operador asignación (double).
    complejo& operator=(double cmr);

    //Operador suma con asignación.
    complejo& operator+=(const complejo &cmrightop);

    //Operador resta con asignación.
    complejo& operator-=(const complejo &cmrightop);

    //Operador producto con asignación.
    complejo& operator*=(const complejo &cmrightop);

    //Operador división con asignación.
    complejo& operator/=(const complejo &cmrightop);

    /* Operadores - End */
};

/* Operadores - Begin */


//Operador menos unario.
complejo operator-(const complejo &cmr);

//Operador suma.
complejo operator+(const complejo &cmleftop, const complejo &cmrightop);

//Operador resta.
complejo operator-(const complejo &cmleftop, const complejo &cmrightop);

//Operador producto.
complejo operator*(const complejo &cmleftop, const complejo &cmrightop);

//Operador división.
complejo operator/(const complejo &cmleftop, const complejo &cmrightop);

//Operador igualdad.
bool operator==(const complejo &cmleftop, const complejo &cmrightop);

//Operador distinto.
bool operator!=(const complejo &cmleftop, const complejo &cmrightop);

//Operador de salida por stream.
std::ostream& operator<<(std::ostream &os, const complejo &cmr);

//Operador de entrada desde stream.
std::istream& operator>>(std::istream &is, complejo &cmr);

/* Operadores - End */


/* Funciones asociadas - Begin */

//Funcción que calcula la exponencial de un complejo.
complejo exp(const complejo &cmarg);

//Función que calcula la potencia de un número double elevado a un complejo.
complejo pow(double dr, complejo cmexp);

//Funciones que calculan la potencia de un número complejo.
complejo pow(const complejo &cmr, int iexp);

complejo pow(const complejo &cmr, double dexp);

complejo pow(const complejo &cmr, complejo cmexp);

//Función que calcula la dft de un vector de complejos.
//Usada para verificar la correctitud de las operaciones comparando
//con valores arrojados por MATLAB.
void dft(complejo *in, complejo *out, int n);

// Función de testeo de la aritmética de complejos
// usando la DFT.
// El resultado se compara luego con lo obtenido
// con MATLAB.
void test_complejo();

/* Funciones asociadas - End */


#endif /* _COMPLEJO_H_INCLUDED_ */
